// -----------------------------
// Author: 		Dhaenens Gert	
// Creation: 	12/29/2013 9:10:08 PM				
// -----------------------------

#include "Vector3.h"
#include "Vector4.h"
#include "Vector2.h"
#include "CMath.h"

/* Constants */
const Vector3 Vector3::Zero = Vector3(0.0f, 0.0f, 0.0f);
const Vector3 Vector3::One = Vector3(1.0f, 1.0f, 1.0f);
const Vector3 Vector3::UnitX = Vector3(1.0f, 0.0f, 0.0f);
const Vector3 Vector3::UnitY = Vector3(0.0f, 1.0f, 0.0f);
const Vector3 Vector3::UnitZ = Vector3(0.0f, 0.0f, 1.0f);

/* Constructors */
Vector3::Vector3()
	: x(0.0f)
	, y(0.0f)
	, z(0.0f)
{
}

Vector3::Vector3(Float X, Float Y, Float Z)
	: x(X)
	, y(Y)
	, z(Z)
{
}

Vector3::Vector3(const Vector3& refVector)
	: x(refVector.x)
	, y(refVector.y)
	, z(refVector.z)
{
}

Vector3::Vector3(const Vector4& refVector)
	: x(refVector.x)
	, y(refVector.y)
	, z(refVector.z)
{
}

Vector3::Vector3(const Vector2& refVector, Float Z)
	: x(refVector.x)
	, y(refVector.y)
	, z(Z)
{
}

Vector3& Vector3::operator=(const Vector3& refVector)
{
	x = refVector.x;
	y = refVector.y;
	z = refVector.z;
	return (*this);
}


/* Comparison Operators */
Bool Vector3::operator==(const Vector3& refVector) const
{
	return (x == refVector.x) &&
		(y == refVector.y) &&
		(z == refVector.z);
}

Bool Vector3::operator!=(const Vector3& refVector) const
{
	return (x != refVector.x) ||
		(y != refVector.y) ||
		(z != refVector.z);
}

Bool Vector3::operator<(const Vector3& refVector) const
{
	return (x < refVector.x) &&
		(y < refVector.y) &&
		(z < refVector.z);
}

Bool Vector3::operator>(const Vector3& refVector) const
{
	return (x > refVector.x) &&
		(y > refVector.y) &&
		(z > refVector.z);
}

Bool Vector3::operator<=(const Vector3& refVector) const
{
	return (x <= refVector.x) &&
		(y <= refVector.y) &&
		(z <= refVector.z);
}

Bool Vector3::operator>=(const Vector3& refVector) const
{
	return (x >= refVector.x) &&
		(y >= refVector.y) &&
		(z >= refVector.z);
}


/* Mathematical In-Place operators */
Vector3& Vector3::operator+=(const Vector3& refVector)
{
	x += refVector.x;
	y += refVector.y;
	z += refVector.z;
	return (*this);
}

Vector3& Vector3::operator-=(const Vector3& refVector)
{
	x -= refVector.x;
	y -= refVector.y;
	z -= refVector.z;
	return (*this);
}

Vector3& Vector3::operator*=(Float fScalar)
{
	x *= fScalar;
	y *= fScalar;
	z *= fScalar;
	return (*this);
}

Vector3& Vector3::operator/=(Float fScalar)
{
	x /= fScalar;
	y /= fScalar;
	z /= fScalar;
	return (*this);
}


/* Mathematical Out-Of-Place Operators */
Vector3 Vector3::operator+(const Vector3& refVector) const
{
	Vector3 tmp(*this);
	tmp += refVector;
	return tmp;
}

Vector3 Vector3::operator-(const Vector3& refVector) const
{
	Vector3 tmp(*this);
	tmp -= refVector;
	return tmp;
}

Vector3 Vector3::operator-() const
{
	return Vector3(-x, -y, -z);
}

Vector3 Vector3::operator*(Float fScalar) const
{
	Vector3 tmp(*this);
	tmp *= fScalar;
	return tmp;
}

Vector3 Vector3::operator/(Float fScalar) const
{
	Vector3 tmp(*this);
	tmp /= fScalar;
	return tmp;
}


/* Mathematical Friend Operators */
Vector3 operator*(Float fScalar, const Vector3& refVector)
{
	return (refVector * fScalar);
}


/* Methods */
Float Vector3::Length() const
{
	return Math::Sqrt(x*x + y*y + z*z);
}

Vector3 Vector3::Normalized() const
{
	Vector3 tmp(*this);
	Float fLength = tmp.Length();
	tmp /= fLength;
	return tmp;
}

Vector3	Vector3::CrossProduct(const Vector3& refVector) const
{
	return Vector3((y * refVector.z) - (z * refVector.y),
				   (z * refVector.x) - (x * refVector.z),
				   (x * refVector.y) - (y * refVector.x));
}

Float Vector3::DotProduct(const Vector3& refVector) const
{
	return (x * refVector.x) + (y * refVector.y) + (z * refVector.z);
}
void Vector3::AsArray(Float arr[3]) const
{
	arr[0] = x;
	arr[1] = y;
	arr[2] = z;
}
Vector3 Vector3::Lerp(const Vector3& other, Float alpha) const
{
	return Vector3(Math::Lerp(x, other.x, alpha),
		Math::Lerp(y, other.y, alpha),
		Math::Lerp(z, other.z, alpha));
}